package paperfile

import (
	"context"
	"io"
	"net/http"

	"paper-pro/app/paperfile/api/internal/svc"
	"paper-pro/app/paperfile/api/internal/types"
	"paper-pro/pkg/ctxdata"
	"paper-pro/pkg/rpc/paperfile/paperfileclient"

	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/logx"
)

type UploadLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// upload and parse paper file
func NewUploadLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UploadLogic {
	return &UploadLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *UploadLogic) Upload(r *http.Request) (resp *types.UploadResponse, err error) {
	stream, err := l.svcCtx.PaperfileRpc.Upload(l.ctx)
	if err != nil {
		return nil, errors.Wrapf(err, "Upload file: PaperfileRpc create stream error: %v", err)
	}

	fileMeta, ok := l.ctx.Value("fileMeta").(map[string]interface{})
	if !ok {
		return nil, errors.Wrapf(err, "Upload file: get fileMeta failed")
	}
	filename := fileMeta["filename"].(string)
	filesize := fileMeta["size"].(int64)
	filetype := fileMeta["type"].(string)
	userId, err := ctxdata.GetUidFromCtx(l.ctx)
	if err != nil {
		return nil, errors.Wrapf(err, "Upload file: get UserId error: %v", err)
	}

	uploadReq := &paperfileclient.UploadReq{
		UploadReqMeta: &paperfileclient.UploadReqMeta{
			FileName:    filename,
			FileSize:    filesize,
			ContentType: filetype,
			UserId:      userId,
		},
	}
	// 流式传输文件
	buf := make([]byte, 1<<20) // 1MB分块
	for {
		n, err := r.Body.Read(buf)
		if err == io.EOF {
			if n > 0 { // 将最后的值传走
				uploadReq.Content = buf[:n]
				if err := stream.Send(uploadReq); err != nil {
					stream.CloseSend()
					return nil, errors.Wrapf(err, "Upload file: stream Send error: %v", err)
				}
			}
			break
		}
		if err != nil {
			stream.CloseSend()
			return nil, errors.Wrapf(err, "Upload file: file Read error: %v", err)
		}

		uploadReq.Content = buf[:n]
		if err := stream.Send(uploadReq); err != nil {
			stream.CloseSend()
			return nil, errors.Wrapf(err, "Upload file: stream Send error: %v", err)
		}
	}

	// 获取响应
	paperfileResp, err := stream.CloseAndRecv()
	if err != nil {
		return nil, errors.Wrapf(err, "Upload file: stream Send error: %v", err)
	}

	return &types.UploadResponse{
		Meta: types.PaperFileMeta{
			Id:          paperfileResp.Meta.Id,
			UpdateAt:    paperfileResp.Meta.UpdateAt,
			CreateAt:    paperfileResp.Meta.CreateAt,
			FileName:    paperfileResp.Meta.FileName,
			FileSize:    paperfileResp.Meta.FileSize,
			ContentType: paperfileResp.Meta.ContentType,
			Status:      paperfileResp.Meta.Status,
			ParseStatus: paperfileResp.Meta.ParseStatus,
		},
	}, nil
}
